﻿using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using CodeContrib.Data.Entity;
using NUnit.Framework;

namespace CodeContrib.Tests.Data.Entity
{
	public class TreeTests
	{
		private CustomTreeContext _context;
		private CustomTree _tree;

		private TreeNode AddTreeNode(TreeNode parentTreeNode)
		{
			var treeNode = (parentTreeNode == null) ? _tree.AddTreeNodeToRoot() : _tree.AddTreeNode(parentTreeNode.Id);

			_context.SaveChanges();

			// Make sure all the tree nodes have been saved correctly.
			_tree = _context.CustomTrees.Find(_tree.Id);

			return treeNode;
		}

		[SetUp]
		public void SetUp()
		{
			var connectionString = string.Format("Data Source=CustomTree.sdf");
			Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0", "", connectionString);
			Database.SetInitializer(new DropCreateDatabaseAlways<CustomTreeContext>());

			_context = new CustomTreeContext(connectionString);

			_tree = new CustomTree();

			_context.CustomTrees.Add(_tree);
			_context.SaveChanges();
		}

		[TearDown]
		public void TearDown()
		{
			if (_context.Database.Exists())
			{
				_context.Database.Delete();
			}
		}

		[Test]
		public void Tree_AddTreeNode_OneLevel_OneChild()
		{
			// Arrange

			// Act
			var treeNode_1_1 = AddTreeNode(_tree.Root());

			// Assert
			//Assert.AreEqual(2, _tree.TreeNodes.Count());

			Assert.AreEqual(0, _tree.Root().Depth);
			Assert.AreEqual(0, _tree.Root().Left);
			Assert.AreEqual(3, _tree.Root().Right);

			Assert.AreEqual(1, treeNode_1_1.Depth);
			Assert.AreEqual(1, treeNode_1_1.Left);
			Assert.AreEqual(2, treeNode_1_1.Right);
		}

		[Test]
		public void Tree_AddTreeNode_OneLevel_TwoChildren()
		{
			// Arrange

			// Act
			var treeNode_1_1 = AddTreeNode(_tree.Root());
			var treeNode_1_2 = AddTreeNode(_tree.Root());

			// Assert
			//Assert.AreEqual(3, _tree.TreeNodes.Count());

			Assert.AreEqual(0, _tree.Root().Depth);
			Assert.AreEqual(0, _tree.Root().Left);
			Assert.AreEqual(5, _tree.Root().Right);

			Assert.AreEqual(1, treeNode_1_1.Depth);
			Assert.AreEqual(1, treeNode_1_1.Left);
			Assert.AreEqual(2, treeNode_1_1.Right);

			Assert.AreEqual(1, treeNode_1_2.Depth);
			Assert.AreEqual(3, treeNode_1_2.Left);
			Assert.AreEqual(4, treeNode_1_2.Right);
		}

		[Test]
		public void Tree_AddTreeNode_TwoLevels_OneChild()
		{
			// Arrange

			// Act
			var treeNode_1_1 = AddTreeNode(_tree.Root());
			var treeNode_2_1 = AddTreeNode(treeNode_1_1);

			// Assert
			//Assert.AreEqual(3, _tree.TreeNodes.Count());

			Assert.AreEqual(0, _tree.Root().Depth);
			Assert.AreEqual(0, _tree.Root().Left);
			Assert.AreEqual(5, _tree.Root().Right);

			Assert.AreEqual(1, treeNode_1_1.Depth);
			Assert.AreEqual(1, treeNode_1_1.Left);
			Assert.AreEqual(4, treeNode_1_1.Right);

			Assert.AreEqual(2, treeNode_2_1.Depth);
			Assert.AreEqual(2, treeNode_2_1.Left);
			Assert.AreEqual(3, treeNode_2_1.Right);
		}

		[Test]
		public void Tree_AddTreeNode_TwoLevels_TwoChildren()
		{
			// Arrange

			// Act
			var treeNode_1_1 = AddTreeNode(_tree.Root());
			var treeNode_2_1 = AddTreeNode(treeNode_1_1);
			var treeNode_2_2 = AddTreeNode(treeNode_1_1);

			var treeNode_1_2 = AddTreeNode(_tree.Root());
			var treeNode_2_3 = AddTreeNode(treeNode_1_2);
			var treeNode_2_4 = AddTreeNode(treeNode_1_2);

			// Assert
			//Assert.AreEqual(7, _tree.TreeNodes.Count());

			Assert.AreEqual(0, _tree.Root().Depth);
			Assert.AreEqual(0, _tree.Root().Left);
			Assert.AreEqual(13, _tree.Root().Right);

			Assert.AreEqual(1, treeNode_1_1.Depth);
			Assert.AreEqual(1, treeNode_1_1.Left);
			Assert.AreEqual(6, treeNode_1_1.Right);

			Assert.AreEqual(2, treeNode_2_1.Depth);
			Assert.AreEqual(2, treeNode_2_1.Left);
			Assert.AreEqual(3, treeNode_2_1.Right);

			Assert.AreEqual(2, treeNode_2_2.Depth);
			Assert.AreEqual(4, treeNode_2_2.Left);
			Assert.AreEqual(5, treeNode_2_2.Right);

			Assert.AreEqual(1, treeNode_1_2.Depth);
			Assert.AreEqual(7, treeNode_1_2.Left);
			Assert.AreEqual(12, treeNode_1_2.Right);

			Assert.AreEqual(2, treeNode_2_3.Depth);
			Assert.AreEqual(8, treeNode_2_3.Left);
			Assert.AreEqual(9, treeNode_2_3.Right);

			Assert.AreEqual(2, treeNode_2_4.Depth);
			Assert.AreEqual(10, treeNode_2_4.Left);
			Assert.AreEqual(11, treeNode_2_4.Right);
		}

		[Test]
		public void Tree_RemoveTreeNode_OneLevel_OneChild()
		{
			// Arrange
			var treeNode_1_1 = AddTreeNode(_tree.Root());

			// Act
			_tree.RemoveTreeNode(treeNode_1_1.Id);

			// Assert
			//Assert.AreEqual(1, _tree.TreeNodes.Count());
		}

		[Test]
		public void Tree_RemoveTreeNode_TwoLevels_OneChild()
		{
			// Arrange
			var treeNode_1_1 = AddTreeNode(_tree.Root());
			AddTreeNode(treeNode_1_1);

			// Act
			_tree.RemoveTreeNode(treeNode_1_1.Id);

			// Assert
			//Assert.AreEqual(1, _tree.TreeNodes.Count());
		}

		[Test]
		public void Tree_ToHierarchyRoot()
		{
			// Arrange
			var treeNode_1_1 = AddTreeNode(_tree.Root());
			AddTreeNode(treeNode_1_1);
			AddTreeNode(treeNode_1_1);

			var treeNode_1_2 = AddTreeNode(_tree.Root());
			AddTreeNode(treeNode_1_2);
			AddTreeNode(treeNode_1_2);

			// Act
			var treeHierarchy = _tree.ToHierarchy();

			// Assert
			Assert.AreEqual(2, treeHierarchy.Children.Count());
			Assert.AreEqual(2, treeHierarchy.Children.ElementAt(0).Children.Count());
			Assert.AreEqual(0, treeHierarchy.Children.ElementAt(0).Children.ElementAt(0).Children.Count());
			Assert.AreEqual(0, treeHierarchy.Children.ElementAt(0).Children.ElementAt(1).Children.Count());
			Assert.AreEqual(2, treeHierarchy.Children.ElementAt(1).Children.Count());
			Assert.AreEqual(0, treeHierarchy.Children.ElementAt(1).Children.ElementAt(0).Children.Count());
			Assert.AreEqual(0, treeHierarchy.Children.ElementAt(1).Children.ElementAt(1).Children.Count());
		}
	}
}